package com.gitee.wsl.mathematics.algebraic

/**
 * Represents ring i.e., algebraic structure with two associative binary operations called "addition" and
 * "multiplication" and their neutral elements.
 *
 * @param T the type of element of this ring.
 */
 interface Ring<T> : Group<T>, RingOps<T> {
    /**
     * The neutral element of multiplication
     */
     val one: T

    /**
     * Raises [arg] to the integer power [pow].
     */
     fun power(arg: T, pow: UInt): T = optimizedPower(arg, pow)

     companion object{
        /**
         * Raises [arg] to the non-negative integer power [exponent].
         *
         * Special case: 0 ^ 0 is 1.
         *
         * @receiver the algebra to provide multiplication.
         * @param arg the base.
         * @param exponent the exponent.
         * @return the base raised to the power.
         * @author Evgeniy Zhelenskiy
         */
        internal fun <T> Ring<T>.optimizedPower(arg: T, exponent: UInt): T = when {
            arg == zero && exponent > 0U -> zero
            arg == one -> arg
            arg == -one -> powWithoutOptimization(arg, exponent % 2U)
            else -> powWithoutOptimization(arg, exponent)
        }

        private fun <T> Ring<T>.powWithoutOptimization(base: T, exponent: UInt): T = when (exponent) {
            0U -> one
            1U -> base
            else -> {
                val pre = powWithoutOptimization(base, exponent shr 1).let { it * it }
                if (exponent and 1U == 0U) pre else pre * base
            }
        }
    }
}